package com.cooper.scraper;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;

import com.cooper.android.comm.ReflectionUtils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;

public class DownloadParams {

	private int retryCount = 2;
	private Handler handler;
	private static Map<String, String> pageBuffer;
	private static Map<String, String> bitmapBuffer;
	private String bitmapCacheDir = "/.cooper_soft";

	private Map<String, Object> completePool = new HashMap<String, Object>();
	private Map<String, Integer> failPool = new HashMap<String, Integer>();
	private Set<String> cancelPool = new HashSet<String>();

	private final Lock resultPoolLock = new ReentrantLock();
	private final Lock failPoolLock = new ReentrantLock();
	private final Lock cancelPoolLock = new ReentrantLock();

	private int connTimeout = 20000;
	private int socketTimeout = 60000;

	private int pageBufferSize = 20;
	private int bitmapBufferSize = 200;

	private int threadPoolSize = 10;
	private int threadMaxSize = 200;
	
	//TODO clear file
	private boolean saveBitmapBufferToFile;

	public DownloadParams() {
		super();
	}

	public DownloadParams(int retryCount, int connTimeout, int socketTimeout) {
		super();
		this.retryCount = retryCount;
		this.connTimeout = connTimeout;
		this.socketTimeout = socketTimeout;
	}

	Handler getHandler() {
		return handler;
	}

	void setHandler(Handler handler) {
		this.handler = handler;
	}

	Map<String, String> getPageBuffer() {
		return pageBuffer;
	}

	void setPageBuffer(Map<String, String> pageBuffer) {
		DownloadParams.pageBuffer = pageBuffer;
	}

	void cacheBitmap(String key, Bitmap bitmap) {
		if (bitmapBuffer != null) {
			String fileName = ReflectionUtils.stringToFileName(key);
			String path = getBitmapCacheDir();
			File chcheFile = new File(path + "/" + fileName);
			if (chcheFile.exists()) {
				chcheFile.delete();
			}
			try {
				OutputStream out = new FileOutputStream(chcheFile);
				try {
					bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out);
					bitmapBuffer.put(key, fileName);
				} finally {
					out.close();
				}
			} catch (IOException e) {
				Log.e("DownloadParams", e.getMessage(), e);
			}

		}
	}

	Bitmap getBitmapFromCache(String key) {
		if (bitmapBuffer != null) {
			String fileName = bitmapBuffer.get(key);
			String path = getBitmapCacheDir();
			File cacheFile = new File(path + "/" + fileName);
			if (cacheFile.exists()) {
				return BitmapFactory.decodeFile(cacheFile.getPath());
			} else {
				return null;
			}
		}
		return null;
	}

	void setBitmapBuffer(Map<String, String> bitmapBuffer) {
		DownloadParams.bitmapBuffer = bitmapBuffer;
	}

	public String getBitmapCacheDir() {
		String result = Environment.getExternalStorageDirectory().toString()
				+ ((bitmapCacheDir.trim().startsWith("/") || bitmapCacheDir
						.trim().startsWith("\\")) ? bitmapCacheDir.trim() : "/"
						+ bitmapCacheDir.trim());
		File defFolder = new File(result);
		if (!defFolder.exists()) {
			defFolder.mkdirs();
		}
		return result;
	}

	public void setBitmapCacheDir(String bitmapCacheDir) {
		this.bitmapCacheDir = bitmapCacheDir;
	}

	public int getRetryCount() {
		return retryCount;
	}

	public void setRetryCount(int retryCount) {
		this.retryCount = retryCount;
	}

	public int getConnTimeout() {
		return connTimeout;
	}

	public void setConnTimeout(int connTimeout) {
		this.connTimeout = connTimeout;
	}

	public int getSocketTimeout() {
		return socketTimeout;
	}

	public void setSocketTimeout(int socketTimeout) {
		this.socketTimeout = socketTimeout;
	}

	public int getThreadPoolSize() {
		return threadPoolSize;
	}

	public void setThreadPoolSize(int threadPoolSize) {
		this.threadPoolSize = threadPoolSize;
	}

	public int getThreadMaxSize() {
		return threadMaxSize;
	}

	public void setThreadMaxSize(int threadMaxSize) {
		this.threadMaxSize = threadMaxSize;
	}

	public int getPageBufferSize() {
		return pageBufferSize;
	}

	public void setPageBufferSize(int pageBufferSize) {
		this.pageBufferSize = pageBufferSize;
	}

	public int getBitmapBufferSize() {
		return bitmapBufferSize;
	}

	public void setBitmapBufferSize(int bitmapBufferSize) {
		this.bitmapBufferSize = bitmapBufferSize;
	}

	public boolean isSaveBitmapBufferToFile() {
		return saveBitmapBufferToFile;
	}

	public void setSaveBitmapBufferToFile(boolean saveBitmapBufferToFile) {
		this.saveBitmapBufferToFile = saveBitmapBufferToFile;
	}

	public void putCancel(String key) {
		cancelPoolLock.lock();
		try {
			cancelPool.add(key);
		} finally {
			cancelPoolLock.unlock();
		}
	}

	public Set<String> cancelKeys() {
		cancelPoolLock.lock();
		try {
			Set<String> result = new HashSet<String>(cancelPool);
			cancelPool.clear();
			return result;
		} finally {
			cancelPoolLock.unlock();
		}
	}

	public void putFail(String key, Integer errorCode) {
		failPoolLock.lock();
		try {
			failPool.put(key, errorCode);
		} finally {
			failPoolLock.unlock();
		}
	}

	public Set<String> failKeys() {
		failPoolLock.lock();
		try {
			return new HashSet<String>(failPool.keySet());
		} finally {
			failPoolLock.unlock();
		}
	}

	public Integer failErrorCode(String key) {
		failPoolLock.lock();
		try {
			Integer result = failPool.get(key);
			failPool.remove(key);
			return result;
		} finally {
			failPoolLock.unlock();
		}
	}

	public void putResult(String key, Object result) {
		resultPoolLock.lock();
		try {
			completePool.put(key, result);
		} finally {
			resultPoolLock.unlock();
		}
	}

	public Set<String> completeKeys() {
		resultPoolLock.lock();
		try {
			return new HashSet<String>(completePool.keySet());
		} finally {
			resultPoolLock.unlock();
		}
	}

	public Object getResult(String key) {
		resultPoolLock.lock();
		try {
			Object result = completePool.get(key);
			completePool.remove(key);
			return result;
		} finally {
			resultPoolLock.unlock();
		}
	}

	public BasicHttpParams createHttpParameters() {
		BasicHttpParams httpParameters = new BasicHttpParams();
		HttpConnectionParams.setConnectionTimeout(httpParameters, connTimeout);
		HttpConnectionParams.setSoTimeout(httpParameters, socketTimeout);
		return httpParameters;
	}
}
